package middleware

import (
	"context"
	"fmt"
	"github.com/goflyfox/gtoken/v2/gtoken"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/text/gstr"
	"net/http"
	userv1 "ruoyi-vue-pro-go/api/user/v1"
	"ruoyi-vue-pro-go/internal/service"
	"ruoyi-vue-pro-go/utility/auth"
)

func MiddlewareAuth(r *ghttp.Request) {

	// 获取当前路由处理函数
	handler := r.GetServeHandler()

	// 方式一: 检查是否有noAuth元数据，如果有且值为true，则跳过验证
	noAuth := handler.GetMetaTag("noAuth")
	if noAuth == "true" {
		r.Middleware.Next()
		return
	}

	// 方式二: 白名单路由，不需要验证
	whiteList := g.Cfg().MustGet(context.Background(), "jwt.whiteList").Strings()
	currentPath := r.Request.URL.Path

	for _, path := range whiteList {
		if gstr.HasPrefix(currentPath, path) {
			r.Middleware.Next()
			return
		}
	}
	// 从请求头获取token
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		r.Response.WriteJsonExit(g.Map{
			"code":    401,
			"message": "未提供认证token",
		})
	}

	// 解析token
	token := authHeader[len("Bearer "):] // 去除"Bearer "前缀
	claims, err := auth.ParseToken(token)
	if err != nil {
		r.Response.WriteJsonExit(g.Map{
			"code":    401,
			"message": "无效的token",
		})
	}

	// 将用户信息存入上下文
	ctx := context.WithValue(r.Context(), "user_id", claims.UserId)
	ctx = context.WithValue(ctx, "username", claims.Username)
	r.SetCtx(ctx)

	// 检查是否需要特定角色
	requiredRole := handler.GetMetaTag("role")
	if requiredRole != "" {
		// 检查用户是否有该角色
		var hasRole = false
		roleList, err := service.User().GetRoleListByUserId(ctx, &userv1.GetRoleListByUserIdReq{
			UserId: claims.UserId,
		})
		for _, role := range roleList.List {
			if role == requiredRole {
				hasRole = true
				break
			}
		}
		if err != nil || !hasRole {
			r.Response.WriteJson(ghttp.DefaultHandlerResponse{
				Code:    403,
				Message: "无权访问",
			})
			return
		}
	}

	r.Middleware.Next()
}

func MiddlewareCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func MiddlewareErrorHandler(r *ghttp.Request) {
	r.Middleware.Next()
	if r.Response.Status >= http.StatusInternalServerError {
		r.Response.ClearBuffer()
		r.Response.Writeln("服务器内部错误，请联系管理员！")
	}
}

// HasPermission 权限校验中间件
func MiddlewareHasPermission(r *ghttp.Request) {
	// 获取当前路由处理函数
	handler := r.GetServeHandler()

	// 方式一: 检查是否有noAuth元数据，如果有且值为true，则跳过验证
	noAuth := handler.GetMetaTag("noAuth")
	if noAuth == "true" {
		r.Middleware.Next()
		return
	}

	// 方式二: 白名单路由，不需要验证
	whiteList := g.Cfg().MustGet(context.Background(), "jwt.whiteList").Strings()
	currentPath := r.Request.URL.Path

	for _, path := range whiteList {
		if gstr.HasPrefix(currentPath, path) {
			r.Middleware.Next()
			return
		}
	}
	// 从请求上下文中获取当前用户信息
	ctx := r.Context()
	user := r.GetCtxVar("user_id")

	if user.IsNil() {
		r.Response.WriteStatusExit(401, "未登录")
		return
	}

	// 检查是否有permission元数据
	permission := handler.GetMetaTag("permission")
	if permission == "" {
		r.Middleware.Next()
		return
	}

	// 这里实现权限校验逻辑
	hasPerm := checkUserPermission(ctx, user, permission)
	if !hasPerm {
		r.Response.WriteStatusExit(403, "无权限访问")
		return
	}

	r.Middleware.Next()
}

// checkUserPermission 检查用户是否有指定权限
func checkUserPermission(ctx context.Context, userId *g.Var, permission string) bool {
	// 尝试从缓存获取
	cacheKey := fmt.Sprintf("user_permissions:%d", userId.Int64())
	value, err := g.Redis().Get(ctx, cacheKey)
	if err != nil {
		g.Log().Debug(ctx, "访问缓存失败")
	}
	permissionsCache := value.Array()
	if len(permissionsCache) > 0 {
		// 缓存命中，检查权限
		g.Log().Debug(ctx, "权限列表缓存命中")
		g.Log().Debug(ctx, "检查权限:", permission)
		for _, p := range permissionsCache {
			if p == permission {
				return true
			}
		}
	}
	// 尝试从数据库获取
	permissions, err := service.User().GetPermissionListByUserId(ctx, &userv1.GetPermissionListByUserIdReq{
		UserId: userId.Int64(),
	})
	if err != nil {
		return false
	}
	if permissions != nil {
		g.Log().Debug(ctx, "从数据库获取权限列表")
		g.Log().Debug(ctx, "检查权限:", permission)
		for _, p := range permissions.List {
			if p == permission {
				return true
			}
		}
	}
	return false
}

func MiddlewareSafeResponse(r *ghttp.Request) {

	r.Middleware.Next()
	// 获取响应数据
	data := r.GetHandlerResponse()
	if m, ok := data.(g.Map); ok {
		delete(m, "password")
		delete(m, "salt")
		r.Response.ClearBuffer()
		r.Response.WriteJson(m)
	}

	// 如果是slice
	if s, ok := data.([]g.Map); ok {
		for _, m := range s {
			delete(m, "password")
			delete(m, "salt")
		}
		r.Response.ClearBuffer()
		r.Response.WriteJson(s)
	}
}

func MiddlewareDesensitize(r *ghttp.Request) {
	r.Middleware.Next()

	// 获取原始响应
	respData := r.GetHandlerResponse()

	// 执行脱敏处理
	safeData := DesensitizeData(respData)

	// 重新设置响应
	r.Response.ClearBuffer()
	r.Response.WriteJson(safeData)
}

// 脱敏处理函数
func DesensitizeData(data interface{}) interface{} {
	switch v := data.(type) {
	case g.Map:
		if mobile, ok := v["mobile"].(string); ok {
			v["mobile"] = mobile[:3] + "****" + mobile[7:]
		}
		if idCard, ok := v["id_card"].(string); ok {
			v["id_card"] = idCard[:6] + "********" + idCard[14:]
		}
		return v

	case []g.Map:
		for _, item := range v {
			DesensitizeData(item)
		}
		return v

	default:
		return data
	}
}

// // 创建gtoken对象
func GetGfToken() gtoken.Token {
	gftoken := gtoken.NewDefaultToken(gtoken.Options{})
	return gftoken
}

//s.Group("/", func(group *ghttp.RouterGroup) {
//	group.Middleware(CORS)
//	// 注册GfToken中间件
//	group.Middleware(gtoken.NewDefaultMiddleware(gfToken).Auth)
//
//	group.ALL("/system/data", func(r *ghttp.Request) {
//		// 获取登陆信息
//		_, data, err := gfToken.Get(r.Context(), r.GetCtxVar(gtoken.KeyUserKey).String())
//		if err != nil {
//			r.Response.WriteJson(RespError(err))
//		}
//		r.Response.WriteJson(RespSuccess(data))
//	})
//	group.ALL("/user/logout", func(r *ghttp.Request) {
//		// 登出销毁Token
//		_ = gfToken.Destroy(ctx, r.GetCtxVar(gtoken.KeyUserKey).String())
//		r.Response.WriteJson(RespSuccess("user logout"))
//	})
//})
//
//s.BindHandler("/login", func(r *ghttp.Request) {
//	// 认证成功调用Generate生成Token
//	token, err := gfToken.Generate(ctx, username, "1")
//	if err != nil {
//		r.Response.WriteJson(RespError(err))
//		r.ExitAll()
//	}
//	r.Response.WriteJson(RespSuccess(g.Map{
//		gtoken.KeyUserKey: username,
//		gtoken.KeyToken:   token,
//	}))
//
//})
